﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Core.h".
//-------------------------------------------------------------------

#ifndef _UXS_STRING_TYPE_H
#define _UXS_STRING_TYPE_H

#pragma once

#include "TAllocator.h"
#include "CopyStrategy.h"
#include "TUniArray.h"
#include "TUniString.h"
#include "../Types/TypesConfig.h"
#include "../BaseTypes/TFixed.h"

namespace UX_STL
{
namespace UXTypes
{

	namespace StringUtils
	{
		template <typename T, typename B>
		usize IntToStr(B val, T * buf, usize size, int radix);
	}
	
	
	template <typename T, usize C, typename S>
	struct TStaticString;


	//
	// String Float Format
	//

	struct StringFormatF
	{
	private:
		uint8	_int;
		uint8	_fract;
		bool	_cutZeros : 1;
		bool	_exponent : 1;

	public:
		StringFormatF () : _int(1), _fract(6), _cutZeros(true), _exponent(false)
		{}

		StringFormatF& Fmt (uint8 intPart, uint8 fractPart = 6)
		{
			_int	= intPart;
			_fract	= fractPart;
			return *this;
		}

		template <typename T>
		StringFormatF& Fmt ()
		{
			_int	= 0;
			_fract	= sizeof(T) == sizeof(float) ? 6 : (sizeof(T) == sizeof(double) ? 8 : 4);
			return *this;
		}

		StringFormatF& CutZeros (bool value = true)
		{
			_cutZeros	= value;
			return *this;
		}

		StringFormatF& Exp (bool value = true)
		{
			_exponent	= value;
			return *this;
		}

		template <usize I>
		void ToCString (char (&cstr)[I]) const
		{
			STATIC_ASSERTE( I > 7 );
			cstr[0] = '%';
			cstr[1] = char('0' + _int / 10);
			cstr[2] = char('0' + _int % 10);
			cstr[3] = '.';
			cstr[4] = char('0' + _fract / 10);
			cstr[5] = char('0' + _fract % 10);
			cstr[6] = _exponent ? 'e' : 'f';
			cstr[7] = 0;
		}

		bool IsCutZeros () const
		{
			return _cutZeros;
		}

		bool IsExponent () const
		{
			return _exponent;
		}
	};

	
	#define _s_uFloatFmt		TStringStaticParams::_s_uFloatFmt
	#define _s_uDoubleFmt		TStringStaticParams::_s_uDoubleFmt
	#define _s_bFloatExp		TStringStaticParams::_s_bFloatExp
	#define _s_bFloatCutZeros	TStringStaticParams::_s_bFloatCutZeros
	#define RET_ERROR( _ret )	{ WARNING("error in string");  return _ret; }
	#define RET_FALSE			RET_ERROR( false )
	#define RET_VOID			RET_ERROR( ; )



	//
	// String
	//
	
	template <	typename T,
				typename S = TFastCopyStrategy<T>,
				typename A = TAllocator<T>
			 >
	struct TString
	{
		friend struct MemMover;

	// types
	public:
		typedef TString<T,S,A>		Self;
		typedef TMemoryViewer<T>	vis_mem_t;
		typedef S					Strategy;
		typedef A					Allocator;
		typedef T					value_t;
		typedef TUniString<T>		uni_str;
		typedef TUniString<const T>	uni_cstr;


	// variables
	private:
		union {
			T		*	_pMemory;
			vis_mem_t	_pVisible;
		};
		usize			_uCount;
		usize			_uSize;

		static const T	_s_aEmpty[1];

		//  _____________________________
		// |  string  |  0  |  reserved  |
		// 0             _uCount        _uSize


	// methods
	private:
		void  _Reallocate (usize uNewSize, bool bReserve = true);
		
		static usize _GetNewSize (usize uNewSize);
		static usize _GetLength (const void *pBegin, const void *pEnd);

		static bool  _IsEmpty (T *p)	{ return (T*)_s_aEmpty == p; } 

	public:
		TString ();
		TString (const Self &sStr);
		TString (const uni_cstr &sStr);

		TString (const char *pStr, usize uLength = 0);
		
		RVALUE_REFERENCE_ONLY(
			TString (Self &&sStr);
		)

		explicit TString (const bool bValue);
		explicit TString (const int iValue);
		explicit TString (const uint uValue);
		explicit TString (const int64 iValue);
		explicit TString (const uint64 uValue);
		explicit TString (const float fValue);
		explicit TString (const double dValue);
		
		template <usize I>
		explicit TString (const TStaticString<T,I,S> &sStr);

		~TString ();

		// добавить в конец строки
		void Append (const void *pBegin, const void *pEnd);
		void Append (const uni_cstr &sStr);
		void Append (const T tValue)										{ return Append( uni_cstr( &tValue, tValue != 0 ) ); }

		// копирует строку
		template <typename B>
		void Copy (const TUniString<B> &sStr);
		void Copy (const uni_cstr &sStr);

		// очищает строку
		void Clear ();
		void ClearMem ();

		// вставляет строку
		void Insert (const void *pBegin, const void *pEnd, usize uPos);
		void Insert (const uni_cstr &sStr, usize uPos);
		void Insert (const T tValue, usize uPos)							{ return Insert( uni_cstr( &tValue, tValue != 0 ), uPos ); }

		// удаляет uCount символов
		void Erase (usize uPos, usize uCount = 1);
		void Erase (const void *pBegin, const void *pEnd);

		// удаляет uCount элементов с конца строки
		void EraseFromBack (usize uCount);

		// пустой ли?
		bool Empty ()	const												{ return _uCount <= 1; }

		// ищет строку и возвращает позицию
		bool Find (const uni_cstr &sStr, OUT usize &uPos, usize uStart = 0)	const	{ return uni_cstr(*this).Find( sStr, uPos, uStart ); }
		bool Find (const T tElem, OUT usize &uPos, usize uStart = 0)		const	{ return uni_cstr(*this).Find( tElem, uPos, uStart ); }
		
		// ищет строку без учета регистра и возвращает позицию
		bool FindI (const uni_cstr &sStr, OUT usize &uPos, usize uStart = 0)const	{ return uni_cstr(*this).FindI( sStr, uPos, uStart ); }
		bool FindI (const T tElem, OUT usize &uPos, usize uStart = 0)		const	{ return uni_cstr(*this).FindI( tElem, uPos, uStart ); }

		// ищет подстроку и удаляет ее
		bool FindAndDelete (const uni_cstr &sStr, OUT usize &uPos, usize uStart = 0);

		// ищет подстроку и заменяет
		bool FindAndChange (const uni_cstr &sStr1, const uni_cstr &sStr2, OUT usize &uPos, usize uStart = 0);

		// при совпадении зменяет символ
		void ChangeChars (const T tFromChar, const T tToChar);

		// удалить символы
		void CutChars (const T tChar);

		// передает строку (без копирования)
		void SetString (INOUT Self &sStr);

		// меняет местами содержимое строк
		void SwapMem (INOUT Self &sStr);

		// устанавливает размер строки
		void SetLength (usize uLength);

		// расчитать длинну строки
		void CalculateLength ();

		// удаляет последний символ
		void PopBack ();

		// изменяет размер строки, заполняя символами новую память
		void Resize (usize uLength, T tChar = T(' '), bool bReserve = true);

		// резервирует место для строки
		void Reserve (usize uSize);

		// освобождает зарезервированную память
		void FreeReserve ();

		// возвращает подстроку
		uni_str		SubString (usize uPos)							{ return uni_str(*this).SubString( uPos ); }
		uni_cstr	SubString (usize uPos)					const	{ return uni_cstr(*this).SubString( uPos ); }
		uni_str		SubString (usize uPos, usize uCount)			{ return uni_str(*this).SubString( uPos, uCount ); }
		uni_cstr	SubString (usize uPos, usize uCount)	const	{ return uni_cstr(*this).SubString( uPos, uCount ); }
		
		// функции форматирования строки
		template <typename B>
		Self &	FormatI (const B& iValue, int iRadix = 10);

		// преобразует целое число в строку вставляя tSpace через каждые uStep символов
		template <typename B>
		Self &	FormatI (const B& iVal, usize uStep, T tSpace, int iRadix = 10);

		// преобразует целое число в строку с заданным выравниванием
		// 100 -> 000100
		template <typename B>
		Self &	FormatAlignedI (const B& iVal, uint align, T tAlignChar = T('0'), int iRadix = 10);

		// преобразует вещественное число в строку в формате:
		// uFmt: 0x01** - количесто знаков перед точкой, 0x**01 - после точки
		Self &	FormatF (float fVal, const StringFormatF &fmt = StringFormatF());
		Self &	FormatF (double fVal, const StringFormatF &fmt = StringFormatF());

		// сравнение строк
		bool CmpPrefix (const uni_cstr &sStr, usize uLength) const		{ return uni_cstr(*this).CmpPrefix( sStr, uLength ); }
		bool CmpPrefix (const T *pStr, usize uLength) const				{ return uni_cstr(*this).CmpPrefix( pStr, uLength ); }
		bool ICmp (const uni_cstr &sStr) const							{ return uni_cstr(*this).ICmp( sStr ); }

		usize GetIndex (const T &elem) const							{ return uni_cstr(*this).GetIndex( elem ); }

		T			*	ptr ()											{ return _pMemory; }
		T const		*	ptr ()								const		{ return _pMemory; }
		T const		*	cstr ()								const		{ return _pMemory; }
		usize			Count ()							const		{ return _uCount; }
		usize			Length ()							const		{ return _uCount-1; }
		usize			Size ()								const		{ return sizeof(T)*_uCount; }
		usize			Capacity ()							const		{ return _uSize; }
		usize			FullSize ()							const		{ return _uSize*sizeof(T); }
		
		T const* const&	ref () const									{ return _pMemory; }
		usize const &	CountRef () const								{ return _uCount; }

		T			*	Begin ()										{ return _pMemory; }
		T const		*	Begin ()							const		{ return _pMemory; }
		T			*	End ()											{ return _pMemory + Length(); }
		T const		*	End ()								const		{ return _pMemory + Length(); }

		T			&	Front ()										{ return _pMemory[0]; }
		T const		&	Front ()							const		{ return _pMemory[0]; }
		T			&	Back ();
		T const		&	Back ()								const;
		
		bool			operator !  ()						const		{ return not Empty(); }
		
		operator		uni_array<T> ()									{ return uni_array<T>( _pMemory, _uCount ); }
		operator const	uni_array<const T> () const						{ return uni_array<const T>( _pMemory, _uCount ); }
		
		operator		uni_str ()										{ return uni_str( _pMemory, Length() ); }
		operator const	uni_cstr () const								{ return uni_cstr( _pMemory, Length() ); }

		T			&	operator [] (usize i);
		T const		&	operator [] (usize i) const;

		Self &			operator =  (const char *pStr)					{ Copy( uni_cstr( pStr ) );	return *this; }
		Self &			operator =  (const uni_cstr &sStr)				{ Copy( sStr );				return *this; }
		Self &			operator =  (const Self &sStr)					{ Copy( sStr );				return *this; }

		template <typename B>
		Self &			operator =  (const B &tValue)					{ Copy( Self( tValue ) );	return *this; }

		bool			operator == (const uni_cstr &sStr)	const		{ return uni_cstr(*this) == sStr; }
		bool			operator != (const uni_cstr &sStr)	const		{ return not ( *this == sStr ); }

		template <typename B>
		Self	operator +  (const B& tValue)				const		{ return Self(*this) += tValue; }
		Self	operator +  (const Self &right)				const		{ return Self(*this) += right; }

		template <typename B> friend
		Self	operator +  (const B& left, const Self &right)			{ return Self(left) += right; }

		template <usize I>
		Self &	operator += (const T aStr[I])							{ return ( *this += uni_cstr(aStr) ); }
		Self &	operator += (const T *pStr)								{ return ( *this += uni_cstr(pStr) ); }
		Self &	operator += (const Self &sStr)							{ return ( *this += uni_cstr(sStr) ); }
		Self &	operator += (const uni_cstr &sStr)						{ Append( sStr );					return *this; }
		Self &	operator += (const T tValue)							{ Append( tValue );					return *this; }
		
		template <typename B>
		Self &	operator += (const B& tValue)							{ Append( Self( tValue ) );			return *this; }

		// запись в конец строки
		template <typename B>
		Self &	operator << (const B& tValue)							{ return (*this += tValue); }

		// запись в начало строки
		template <typename B>
		friend Self &	operator >> (const B& left, Self &right)		{ right.Insert( Self( left ), 0 );	return right; }
		friend Self &	operator >> (const uni_cstr &left, Self &right)	{ right.Insert( left, 0 );			return right; }
		friend Self &	operator >> (const T left, Self &right)			{ right.Insert( left, 0 );			return right; }

		// сравнение строк для сортировки
		bool	operator < (const uni_cstr &sStr)	const				{ return uni_cstr(*this) < sStr; }
		bool	operator > (const uni_cstr &sStr)	const				{ return uni_cstr(*this) > sStr; }
		bool	operator <= (const uni_cstr &sStr)	const				{ return uni_cstr(*this) <= sStr; }
		bool	operator >= (const uni_cstr &sStr)	const				{ return uni_cstr(*this) >= sStr; }
		bool	NumStrLess (const uni_cstr &sStr)	const				{ return uni_cstr(*this).NumStrLess( sStr ); }

		template <typename T2, typename S2, typename A2>
		void Convert (OUT TString<T2,S2,A2> &sStr) const;


		inline friend bool operator == (const T * const left, const Self &right)
		{
			return right == left;
		}
		
		inline friend bool operator != (const T * const left, const Self &right)
		{
			return right != left;
		}
	};

	
	template <typename T, typename S, typename A>
	const T		TString<T,S,A>::_s_aEmpty[1] = {0};


	typedef TString< char,  TFastCopyStrategy<char>,  TAllocator<char>  >		string;
	typedef	TString< wchar, TFastCopyStrategy<wchar>, TAllocator<wchar> >		wstring;




	template <typename T, typename S, typename A>
	inline TString<T,S,A>::TString(): _pMemory((T*)_s_aEmpty), _uCount(1), _uSize(1)
	{
	}
	
	
	template <typename T, typename S, typename A>
	inline TString<T,S,A>::TString(const char *pStr, usize uLength):
		_pMemory((T*)_s_aEmpty), _uCount(1), _uSize(1)
	{
		Copy( uni_cstr( pStr, uLength == 0 and pStr != null ? StringUtils::Length( pStr ) : uLength ) );
	}
		
	
	template <typename T, typename S, typename A>
	inline TString<T,S,A>::TString(const Self &sStr):
		_pMemory((T*)_s_aEmpty), _uCount(1), _uSize(1)
	{
		Copy( uni_cstr( sStr ) );
	}
	

	RVALUE_REFERENCE_ONLY(
		template <typename T, typename S, typename A>
		inline TString<T,S,A>::TString(Self &&sStr):
			_pMemory((T*)_s_aEmpty), _uCount(1), _uSize(1)
		{
			SetString( sStr );
		}
	)


	template <typename T, typename S, typename A>
	inline TString<T,S,A>::TString(const uni_cstr &sStr): _pMemory((T*)_s_aEmpty), _uCount(1), _uSize(1)
	{
		Copy( sStr );
	}

	
	template <typename T, typename S, typename A>
	inline TString<T,S,A>::TString(const bool bValue): _pMemory((T*)_s_aEmpty), _uCount(1), _uSize(1)
	{
		Copy( bValue ? "true" : "false" );
	}


	template <typename T, typename S, typename A>
	inline TString<T,S,A>::TString(const int iValue): _pMemory((T*)_s_aEmpty), _uSize(1), _uCount(1)
	{
		FormatI( iValue, CoreTypesConfig::StringDefaultRadix );
	}


	template <typename T, typename S, typename A>
	inline TString<T,S,A>::TString(const uint uValue): _pMemory((T*)_s_aEmpty), _uSize(1), _uCount(1)
	{
		FormatI( uValue, CoreTypesConfig::StringDefaultRadix );
	}
	

	template <typename T, typename S, typename A>
	inline TString<T,S,A>::TString(const int64 iValue): _pMemory((T*)_s_aEmpty), _uSize(1), _uCount(1)
	{
		FormatI( iValue, CoreTypesConfig::StringDefaultRadix );
	}
	

	template <typename T, typename S, typename A>
	inline TString<T,S,A>::TString(const uint64 iValue): _pMemory((T*)_s_aEmpty), _uSize(1), _uCount(1)
	{
		FormatI( iValue, CoreTypesConfig::StringDefaultRadix );
	}


	template <typename T, typename S, typename A>
	inline TString<T,S,A>::TString(const float fValue): _pMemory((T*)_s_aEmpty), _uSize(1), _uCount(1)
	{
		FormatF( fValue, StringFormatF().Fmt<float>().CutZeros() );
	}


	template <typename T, typename S, typename A>
	inline TString<T,S,A>::TString(const double dValue): _pMemory((T*)_s_aEmpty), _uSize(1), _uCount(1)
	{
		FormatF( dValue, StringFormatF().Fmt<double>().CutZeros() );
	}


	template <typename T, typename S, typename A>
	inline TString<T,S,A>::~TString()
	{
		if ( _pMemory != (T*)_s_aEmpty )
			Allocator::Deallocate( _pMemory );
	}

	
	template <typename T, typename S, typename A>
	inline void TString<T,S,A>::_Reallocate(usize uNewSize, bool bReserve)
	{
		_uSize			= bReserve ? _GetNewSize(uNewSize) : uNewSize;
		T	*	p_old	= _pMemory;
		usize	u_count	= _uCount < uNewSize ? _uCount : uNewSize;
		_pMemory		= Allocator::Allocate( _uSize );

		if ( _IsEmpty( p_old ) ) {
			_pMemory[0] = 0;
			_uCount = 1;
			return;
		}

		Strategy::Replace( _pMemory, p_old, u_count );

		if ( u_count < _uCount )
			Strategy::Destroy( p_old + u_count, _uCount - u_count );

		_uCount = u_count;

		Allocator::Deallocate( p_old );
	}
	
	
	template <typename T, typename S, typename A>
	inline usize TString<T,S,A>::_GetLength(const void *pBegin, const void *pEnd)
	{
		ASSERT( pBegin <= pEnd );
		return ( usize(pEnd) - usize(pBegin) ) / sizeof(T);
	}

	
	template <typename T, typename S, typename A>
	inline usize TString<T,S,A>::_GetNewSize(usize uNewSize)
	{
		const usize	nom		 = CoreTypesConfig::StringResizingNominator;
		const usize	den		 = CoreTypesConfig::StringResizingDenominator;
		const usize	min_size = CoreTypesConfig::StringResizingMinSize;
		const usize	temp	 = (uNewSize * nom + den - 1) / den;
		return ( uNewSize + (temp < min_size ? min_size : temp) );
	}
		

	template <typename T, typename S, typename A>
	inline T &  TString<T,S,A>::Back()
	{
		ASSUME( _uCount >= 2 );
		return _pMemory[_uCount-2];
	}
		

	template <typename T, typename S, typename A>
	inline const T & TString<T,S,A>::Back() const
	{
		ASSUME( _uCount >= 2 );
		return _pMemory[_uCount-2];
	}

		
	template <typename T, typename S, typename A>
	inline T & TString<T,S,A>::operator [] (usize uNumb)
	{
		ASSUME( uNumb < _uCount );
		return _pMemory[uNumb];
	}
		

	template <typename T, typename S, typename A>
	inline const T & TString<T,S,A>::operator [] (usize uNumb) const
	{
		ASSUME( uNumb < _uCount );
		return _pMemory[uNumb];
	}


	template <typename T, typename S, typename A>
	inline void TString<T,S,A>::Append(const uni_cstr &sStr)
	{
		if ( sStr.Empty() ) 
			return;

		const usize	u_old = Length();

		if ( _uCount + sStr.Length() > _uSize )
			_Reallocate( _uCount + sStr.Length() );

		_uCount += sStr.Length();

		Strategy::Copy( _pMemory + u_old, sStr.ptr(), sStr.Length() );
		_pMemory[_uCount-1] = 0;
	}
	
	
	template <typename T, typename S, typename A>
	inline void TString<T,S,A>::Append(const void *pBegin, const void *pEnd)
	{
		Append( (const T *)pBegin, _GetLength( pBegin, pEnd ) );
	}


	template <typename T, typename S, typename A>
	template <typename B>
	inline void TString<T,S,A>::Copy(const TUniString<B> &sStr)
	{
		if ( sStr.Empty() or (void *)sStr.ptr() == (void *)_pMemory ) {
			Clear();
			return;
		}

		if ( sStr.Length() >= _uSize )
		{
			_uSize = _GetNewSize( sStr.Length()+1 );

			if ( not _IsEmpty( _pMemory ) )
				Allocator::Deallocate( _pMemory );
			
			_pMemory = Allocator::Allocate( _uSize );
		}

		for (usize i = 0; i < sStr.Length(); ++i)
			_pMemory[i] = (T)sStr[i];

		_pMemory[ sStr.Length() ] = 0;
		_uCount = sStr.Length() + 1;
	}


	template <typename T, typename S, typename A>
	inline void TString<T,S,A>::Copy(const uni_cstr &sStr)
	{
		if ( sStr.Empty() or sStr.ptr() == _pMemory ) {
			Clear();
			return;
		}

		if ( sStr.Length() >= _uSize )
		{
			_uSize = _GetNewSize( sStr.Length()+1 );
			
			if ( not _IsEmpty( _pMemory ) )
				Allocator::Deallocate( _pMemory );
			
			_pMemory = Allocator::Allocate( _uSize );
		}

		Strategy::Copy( _pMemory, sStr.ptr(), sStr.Length() );

		_pMemory[ sStr.Length() ] = 0;
		_uCount = sStr.Length() + 1;
	}


	template <typename T, typename S, typename A>
	inline void TString<T,S,A>::Clear()
	{
		if ( _IsEmpty( _pMemory ) )
			return;

		if ( _uSize > CoreTypesConfig::StringResizingMinSize )
		{
			Allocator::Deallocate( _pMemory );
			_pMemory = (T*)_s_aEmpty;
			_uCount  = 1;
			_uSize   = 1;
		}
		else
		{
			_pMemory[0]	= 0;
			_uCount		= 1;
		}
	}
	

	template <typename T, typename S, typename A>
	inline void TString<T,S,A>::ClearMem()
	{
		if ( _IsEmpty( _pMemory ) )
			return;

		_pMemory[0] = 0;
		_uCount		= 1;
	}


	template <typename T, typename S, typename A>
	inline void TString<T,S,A>::Insert(const uni_cstr &sStr, usize uPos)
	{
		if ( sStr.Empty() or uPos >= _uCount or sStr.ptr() == _pMemory )
			return;

		_uCount += sStr.Length();

		T	*	p_old	  = _pMemory;
		bool	b_resized = false;

		if ( _uCount > _uSize )
		{
			b_resized = not _IsEmpty( p_old );
			_uSize	  = _GetNewSize( _uCount );
			_pMemory  = Allocator::Allocate( _uSize );

			Strategy::Replace( _pMemory, p_old, uPos );
			Strategy::Replace( _pMemory + uPos + sStr.Length(), p_old + uPos, _uCount - sStr.Length() - uPos - 1 );
		}
		else
		{
			isize	i_temp = uPos + sStr.Length();
			for (isize i = _uCount-1; i >= i_temp; --i)
				Strategy::Replace( _pMemory + i, p_old[i - sStr.Length()] );
		}

		Strategy::Copy( _pMemory + uPos, sStr.ptr(), sStr.Length() );
		_pMemory[_uCount-1] = 0;

		if ( b_resized )
			Allocator::Deallocate( p_old );
	}
	

	template <typename T, typename S, typename A>
	inline void TString<T,S,A>::Insert(const void *pBegin, const void *pEnd, usize uPos)
	{
		Insert( uni_cstr( (const T*)pBegin, _GetLength( pBegin, pEnd ) ), uPos );
	}


	template <typename T, typename S, typename A>
	inline void TString<T,S,A>::Erase(usize uPos, usize uCount)
	{
		if ( uPos >= Length() or uCount == 0 )
			RET_VOID;
		
		if ( uPos + uCount > _uCount )
			uCount = _uCount - uPos;

		_uCount -= uCount;

		for (usize i = 0; i < _uCount - uPos; ++i)
			Strategy::Replace( _pMemory + uPos + i, _pMemory[uPos + uCount + i] );
	}
	

	template <typename T, typename S, typename A>
	inline void TString<T,S,A>::Erase(const void *pBegin, const void *pEnd)
	{
		ASSERT( pBegin < pEnd );
		if ( pBegin < (void *)Begin() or pEnd >= (void *)End() )
			RET_VOID;

		Erase( GetIndex( *pBegin ), _GetLength( pBegin, pEnd ) );
	}
	

	template <typename T, typename S, typename A>
	inline void TString<T,S,A>::EraseFromBack(usize uCount)
	{
		ASSERT( uCount < _uCount );

		if ( uCount >= _uCount-1 ) {
			Clear();
			return;
		}

		//Strategy::Destroy( _pMemory + _uCount - uCount, uCount );
		_uCount -= uCount;
		_pMemory[_uCount-1] = 0;
	}


	template <typename T, typename S, typename A>
	inline void TString<T,S,A>::Reserve(usize uSize)
	{
		if ( uSize == 0 or ( (uSize <= _uCount or uSize <= _uSize) and not _IsEmpty( _pMemory ) ) )
			return;

		_Reallocate( uSize, false );
	}

	
	template <typename T, typename S, typename A>
	inline void TString<T,S,A>::Resize(usize uLength, T tChar, bool bReserve)
	{
		if ( uLength >= _uSize )
			_Reallocate( uLength+1, bReserve );
		
		const isize	i_delta = (isize)( uLength - Length() );

		for (isize i = i_delta; i > 0; --i)
			_pMemory[ uLength - i ] = tChar;

		_uCount = uLength+1;
		_pMemory[uLength] = 0;
	}


	template <typename T, typename S, typename A>
	inline void TString<T,S,A>::FreeReserve()
	{
		if ( _uCount > _uSize )
			_Reallocate( _uCount, false );
	}


	template <typename T, typename S, typename A>
	inline bool TString<T,S,A>::FindAndDelete(const uni_cstr &sStr, usize &uPos, usize uStart)
	{
		if ( not Find( sStr, uPos, uStart ) )
			return false;

		return Erase( uPos, sStr.Length() );
	}


	template <typename T, typename S, typename A>
	inline bool TString<T,S,A>::FindAndChange(const uni_cstr &sStr1, const uni_cstr &sStr2, usize &uPos, usize uStart)
	{
		usize	u_len = Min( sStr1.Length(), sStr2.Length() ),
				i = 0;

		if ( not Find( sStr1, uPos, uStart ) )
			return false;

		for (i = 0; i < u_len; ++i) {
			_pMemory[i+uPos] = sStr2[i];
		}

		if ( sStr1.Length() > u_len )
			Erase( i+uPos, sStr1.Length() - u_len );

		if ( sStr2.Length() > u_len )
			Insert( uni_cstr( sStr2.cstr() + i, sStr2.Length()-i ), uPos+i );
		
		return true;
	}

		
	template <typename T, typename S, typename A>
	inline void TString<T,S,A>::ChangeChars(const T tFromChar, const T tToChar)
	{
		if ( tFromChar == 0 or tToChar == 0 )
			RET_VOID;

		for (usize i = 0; i < _uCount-1; ++i) {
			if ( _pMemory[i] == tFromChar )
				_pMemory[i] = tToChar;
		}
	}

		
	template <typename T, typename S, typename A>
	inline void TString<T,S,A>::CutChars(const T tChar)
	{
		usize	u_step	= 0;
		usize	i		= 0;

		for (; i < Length(); ++i)
		{
			if ( _pMemory[i] == tChar )
			{
				u_step = 1;
				++i;
				break;
			}
		}

		for (; i < Length(); ++i)
		{
			if ( _pMemory[i] == tChar ) {
				++u_step;
				continue;
			}

			_pMemory[i-u_step] = _pMemory[i];
		}
	}


	template <typename T, typename S, typename A>
	inline void TString<T,S,A>::SetString(TString<T,S,A> &sStr)
	{
		if ( not _IsEmpty( _pMemory ) )
			Allocator::Deallocate( _pMemory );

		_pMemory = sStr._pMemory;
		_uCount  = sStr._uCount;
		_uSize   = sStr._uSize;

		sStr._pMemory = (T*)_s_aEmpty;
		sStr._uCount  = 1;
		sStr._uSize   = 1;
	}

	
	template <typename T, typename S, typename A>
	inline void TString<T,S,A>::SwapMem(TString<T,S,A> &sStr)
	{
		_swap( _pMemory,	sStr._pMemory );
		_swap( _uCount,		sStr._uCount );
		_swap( _uSize,		sStr._uSize );
	}

	
	template <typename T, typename S, typename A>
	inline void TString<T,S,A>::SetLength(usize uLength)
	{
		if ( uLength+1 > _uSize )
			RET_VOID;

		_uCount = uLength + 1;
		_pMemory[uLength] = 0;
	}

	
	template <typename T, typename S, typename A>
	inline void TString<T,S,A>::CalculateLength ()
	{
		SetLength( StringUtils::Length( cstr() ) );
	}

	
	template <typename T, typename S, typename A>
	inline void TString<T,S,A>::PopBack()
	{
		if ( Length() == 0 )
			RET_VOID;
		
		--_uCount;
		_pMemory[ Length() ] = 0;
	}
	
	
	template <typename T, typename S, typename A>
	template <typename B>
	inline TString<T,S,A> & TString<T,S,A>::FormatI(const B& iValue, int iRadix)
	{
		Reserve( (sizeof(iValue)<<3) + 2 );
		_uCount = StringUtils::IntToStr( iValue, _pMemory, _uSize, iRadix ) + 1;
		return *this;
	}
	

	template <typename T, typename S, typename A>
	template <typename B>
	inline TString<T,S,A> & TString<T,S,A>::FormatAlignedI(const B& iValue, uint align, T tAlignChar, int iRadix)
	{
		Reserve( UXMath::Max<uint>( (sizeof(iValue)<<3) + 2, align ) );
		_uCount = StringUtils::IntToStr( iValue, _pMemory, _uSize, iRadix ) + 1;

		align += 1;

		if ( _uCount < align )
		{
			Strategy::Replace( _pMemory + align - _uCount, _pMemory, _uCount );
		
			for (uint i = 0; i < align - _uCount; ++i)
			{
				_pMemory[i] = tAlignChar;
			}
			_uCount = align;
		}
		return *this;
	}
	

	template <typename T, typename S, typename A>
	template <typename B>
	inline TString<T,S,A> & TString<T,S,A>::FormatI(const B& iVal, usize uStep, T tSpace, int iRadix)
	{
		if ( uStep == 0 ) {
			WARNING( "invalid argument" );
			return *this;
		}

		char	a_buf[ (sizeof(iVal)<<3) + 2 ] = {0};

		isize	i	= StringUtils::IntToStr( iVal, a_buf, CountOf(a_buf), iRadix ),
				j	= 0,
				k	= k	= i + i / uStep - (i % uStep == 0 ? 1 : 0);;

		Reserve( k+2 );
		SetLength( k );

		for (--i; (i >= 0 and k != 0); --i)
		{
			_pMemory[--k] = (T)a_buf[i];

			if ( ++j >= (isize)uStep and k != 0 ) {
				_pMemory[--k] = tSpace;
				j = 0;
			}
		}

		return *this;
	}

	
	template <typename T, typename S, typename A>
	inline TString<T,S,A> & TString<T,S,A>::FormatF(float fValue, const StringFormatF &fmt)
	{
		const float		value	= UXMath::Abs(fValue);
		StringFormatF	format	= fmt;

		if ( value > 1.0e7f or ( value > 0.0f and value < 1.0e-6f ) )
			format.Exp();

		char	a_fmt[8] = {};
		format.ToCString( a_fmt );

		Reserve( (sizeof(fValue)<<4) / 10 + 10 );
		
		_uCount = _hidden_::sprintf( _pMemory, a_fmt, fValue ) + 1;

		if ( (isize)_uCount <= 0 ) {
			WARNING( "can't convert value to string" );
			return *this;
		}

		if ( format.IsCutZeros() and not format.IsExponent() )
		{
			for (isize i = _uCount-2; i > 0; --i)
			{
				if ( _pMemory[i] == (T)'0' )	_uCount = i;
				else {
					_uCount = i+2 + (_pMemory[i] == (T)'.');
					break;
				}
			}
			_pMemory[_uCount-1] = T(0);
		}

		return *this;
	}

	
	template <typename T, typename S, typename A>
	inline TString<T,S,A> & TString<T,S,A>::FormatF(double fValue, const StringFormatF &fmt)
	{
		const double	value	= UXMath::Abs(fValue);
		StringFormatF	format	= fmt;
		
		if ( value > 1.0e13 or ( value > 0.0 and value < 1.0e-7 ) )
			format.Exp();

		char	a_fmt[8] = {};
		format.ToCString( a_fmt );

		Reserve( (sizeof(fValue)<<4) / 10 + 12 );
		
		_uCount = _hidden_::sprintf( _pMemory, a_fmt, fValue ) + 1;

		if ( (isize)_uCount <= 0 ) {
			WARNING( "can't convert value to string" );
			return *this;
		}
		
		if ( format.IsCutZeros() and not format.IsExponent() )
		{
			for (isize i = _uCount-2; i > 0; --i)
			{
				if ( _pMemory[i] == (T)'0' )	_uCount = i;
				else {
					_uCount = i+2 + (_pMemory[i] == (T)'.');
					break;
				}
			}
			_pMemory[_uCount-1] = T(0);
		}

		return *this;
	}
	
	
	template <typename T, typename S, typename A>
	template <typename T2, typename S2, typename A2>
	inline void TString<T,S,A>::Convert(TString<T2,S2,A2> &sStr) const
	{
		sStr.Reserve( _uCount+3 );

		for (usize i = 0; i < _uCount; ++i) {
			sStr[i] = (T2)_pMemory[i];
		}

		sStr.SetLength( Length() );
	}
	
	
	#undef  RET_ERROR
	#undef	RET_FALSE
	#undef  RET_VOID

//-------------------------------------------------------------------

}	// UXTypes
}	// UX_STL

#endif	// _UXS_STRING_TYPE_H